#include "Service.h"
#include "Sunnet.h"
#include <memory>
#include <unistd.h>
#include <string.h>
#include "LuaAPI.h"
using namespace std;

//构造函数
Service::Service(){
    //初始化锁
    pthread_spin_init(&queueLock, PTHREAD_PROCESS_PRIVATE);
    pthread_spin_init(&inGlobalLock, PTHREAD_PROCESS_PRIVATE);
}

//析构函数
Service::~Service(){
    pthread_spin_destroy(&queueLock);
    pthread_spin_destroy(&inGlobalLock);
}

void Service::SetInGlobal(bool isIn){
    pthread_spin_lock(&inGlobalLock);
    {
        inGlobal = isIn;
    }
    pthread_spin_unlock(&inGlobalLock);
}

//创建服务后触发
void Service::OnInit(){
    //新建Lua虚拟机
    luaState = luaL_newstate();
    luaL_openlibs(luaState);
    //注册Sunnet系统API
    LuaAPI::Register(luaState);

    //执行lua文件
    string filename = "../service/" + *type + "/init.lua";
    int isok = luaL_dofile(luaState, filename.data());
    //成功返回0,失败返回1
    if(isok == 1){
        cout << "[Service][OnInit] luaL_dofile fail:" << lua_tostring(luaState, -1) << endl;
        return;
    }
    //调用Lua函数
    lua_getglobal(luaState, "OnInit");
    lua_pushinteger(luaState, id);
    isok = lua_pcall(luaState, 1, 0, 0);
    if(isok != 0 ){
        cout << "[Service][OnInit] lua_pcall fail " << lua_tostring(luaState, -1) << endl;
        return;
    }
}

//退出服务时触发
void Service::OnExit(){
    //调用Lua函数
    lua_getglobal(luaState, "OnExit"); 
    int isok = lua_pcall(luaState, 0, 0, 0);
    if(isok != 0 ){
        cout << "[Service][OnExit] lua_pcall fail " << lua_tostring(luaState, -1) << endl;
        return;
    }
    //关闭虚拟机
    lua_close(luaState);
}

//收到消息后触发
void Service::OnMsg(shared_ptr<BaseMsg> msg){
    //Service
    if(msg->type == BaseMsg::TYPE::SERVICE){
        auto m = dynamic_pointer_cast<ServiceMsg>(msg);
        OnServiceMsg(m);
    }
    //SOCKET_ACCEPT
    else if(msg->type == BaseMsg::TYPE::SOCKET_ACCEPT){
        auto m = dynamic_pointer_cast<SocketAcceptMsg>(msg);
        OnAcceptMsg(m);
    }
    //SOCKET_RW
    else if(msg->type == BaseMsg::TYPE::SOCKET_RW){
        auto m = dynamic_pointer_cast<SocketRWMsg>(msg);
        OnRWMsg(m);
    }
}

//插入消息
void Service::PushMsg(shared_ptr<BaseMsg> msg){
    pthread_spin_lock(&queueLock);
    {
        msgQueue.push(msg);
    }
    pthread_spin_unlock(&queueLock);
}

//处理一条消息,返回值代表是否处理
bool Service::ProcessMsg(){
    shared_ptr<BaseMsg> msg = PopMsg();
    if(msg){
        OnMsg(msg);
        return true;
    }
    else{
        return false;   //返回值表示队列是否为空
    }
}

//处理N条消息,返回值代表是否处理
void Service::ProcessMsgs(int max){
    for(int i=0; i<max; i++){
        bool succ = ProcessMsg();
        if(!succ){
            break;
        }
    }
}

//取出消息
shared_ptr<BaseMsg> Service::PopMsg(){
    shared_ptr<BaseMsg> msg = NULL;
    //取一条消息
    pthread_spin_lock(&queueLock);
    {
        if(!msgQueue.empty()){
            msg = msgQueue.front();
            msgQueue.pop();
        }
    }
    pthread_spin_unlock(&queueLock);
    return msg;
}

//服务间消息
void Service::OnServiceMsg(shared_ptr<ServiceMsg> msg){
    //调用Lua函数
    lua_getglobal(luaState, "OnServiceMsg");
    lua_pushinteger(luaState, msg->source);
    lua_pushlstring(luaState, msg->buff.get(), msg->size);
    int isok = lua_pcall(luaState, 2, 0, 0);
    if(isok != 0){ //若返回值为0则代表成功,否则代表失败
        cout << "[Service][OnServiceMsg] lua OnServiceMsg fail" << lua_tostring(luaState, -1) << endl;
    }
}

//有新连接
void Service::OnAcceptMsg(shared_ptr<SocketAcceptMsg> msg){
    cout << "[Service][OnAcceptMsg] client:" << msg->clientFd << endl;
    auto w = make_shared<ConnWriter>();
    w->fd = msg->clientFd;
    writers.emplace(msg->clientFd, w);
    //调用Lua函数
    lua_getglobal(luaState, "OnAcceptMsg");
    lua_pushinteger(luaState, msg->listenFd);
    lua_pushinteger(luaState, msg->clientFd);
    int isok = lua_pcall(luaState, 2, 0, 0);
    //若返回值为0则代表成功,否则代表成功
    if(isok != 0){
        cout << "[Service][OnAcceptMsg] lua_pcall fail " << lua_tostring(luaState, -1) << endl;
    }
}

//关闭连接前
void Service::OnSocketClose(int fd){
    cout << "[Service][OnSocketClose] fd:" << fd << endl;
    writers.erase(fd);
     //调用Lua函数
     lua_getglobal(luaState, "OnSocketClose");
     lua_pushinteger(luaState, fd); 
     int isok = lua_pcall(luaState, 1, 0, 0);
     //若返回值为0则代表成功,否则代表成功
     if(isok != 0){
         cout << "[Service][OnSocketData] lua_pcall fail " << lua_tostring(luaState, -1) << endl;
     }
}

//套接字可写
void Service::OnSocketWritable(int fd){
    cout << "[Service][OnSocketWritable] fd:" << fd << endl;
    auto w = writers[fd];
    w->OnWriteable();
}

//读写消息
void Service::OnRWMsg(shared_ptr<SocketRWMsg> msg){
    int fd = msg->fd;
    //可读
    if(msg->isRead){
        const int BUFFSIZE = 5112;
        char buff[BUFFSIZE];
        int len = 0;
        do{
            len = read(fd, &buff, BUFFSIZE);
            if(len > 0){
                OnSocketData(fd, buff, len);
            }
        }while(len == BUFFSIZE);

        if(len <= 0 && errno != EAGAIN){
            if(Sunnet::inst->GetConn(fd)){
                OnSocketClose(fd);
                Sunnet::inst->CloseConn(fd);
            }
        }
    }
    //可写(注意没有else)
    if(msg->isWrite){
        if(Sunnet::inst->GetConn(fd)){
            OnSocketWritable(fd);
        }
    }
}

void Service::OnSocketData(int fd, const char* buff, int len){
    cout << "[Service][OnSocketData] fd:" << fd <<  " len:" << len << " buff:" << buff << endl;
    // //echo
    // char wirteBuff[3] = {'l','p','y'};
    // write(fd, &wirteBuff, 3);
    // //等待15秒继续发送
    // usleep(15000000);
    // char wirteBuff2[3] = {'n','e','t'};
    // int r = write(fd, &wirteBuff2, 3);
    // cout << "write2 r:" << r << " " << strerror(errno) << endl;
    // //等待1秒，继续发送
    // char wirteBuff3[2] = {'n','o'};
    // r = write(fd, &wirteBuff3, 2);
    // cout << "write3 r:" << r << " " << strerror(errno) << endl;

    // //发送大数据实验
    // char* writeBuff = new char[4200000];
    // writeBuff[4200000-1] = 'e';
    // int r = write(fd, writeBuff, 4200000);
    // cout << "write r:" << r << " " << strerror(errno) << endl;

    //用ConnWriter发送大量数据
    // char* wirteBuff = new char[4200000];
    // wirteBuff[4200000-1] = 'e';
    // int r = write(fd, wirteBuff, 42000000);
    // cout << "write r:" << r << " " << strerror(errno) << endl;
    // auto w = writers[fd];
    // w->EntireWrite(shared_ptr<char>(wirteBuff), 4200000);
    // w->LingerClose();

    //调用Lua函数
    lua_getglobal(luaState, "OnSocketData");
    lua_pushinteger(luaState, fd);
    lua_pushlstring(luaState, buff, len);
    int isok = lua_pcall(luaState, 2, 0, 0);
    //若返回值为0则代表成功,否则代表成功
    if(isok != 0){
        cout << "[Service][OnSocketData] lua_pcall fail " << lua_tostring(luaState, -1) << endl;
    }
}